﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Vision.Common.Common;

namespace Vision.Common
{
    public partial class UCPreView : UserControl
    {
        #region 委托
        /// <summary>
        /// 鼠标移动时更新位置
        /// </summary>
        [Description("鼠标移动时更新鼠标在图像中位置")]
        public event EventHandler<PosArgs> OnUpdatePos;
        //public event EventHandler<Graphics> OnPaint;
        #endregion

        float m_zoomLevel = 1.1f;    //滚动缩放等级
        Font m_font = new Font("微软雅黑", 15);
        PointF m_imgOrgInPic = new PointF(0, 0);        //图像原点在画布中位置    //e.X（鼠标位置）=m_imgOrgInPic.X+m_curPosInImg.X*m_imgZoom
        public PointF ImgOrgInPic { get => m_imgOrgInPic; }
        PointF m_curPosInImg = new Point(0, 0);         //鼠标（画布）位置在图像中坐标
        public PointF CurPosInImg { get => m_curPosInImg; }
        //List<DrawImg> ImgItems = new List<DrawImg>();
        Bitmap canvasImg = null;    //当前画布图像
        //Bitmap canvasImgBackup = null;    //当前画布图像
        Rectangle canvasImgRect = default;
        //List<DrawImg> ImgItemsDraw = new List<DrawImg>();
        public List<CDrawObj> m_objList = new List<CDrawObj>();
        Point lastMousePt;
        Point curMousePt;
        public CDrawRect curDrawObj = null;
        bool m_isCtrl = false;//Ctrl键是否按下
        bool m_isLMouseDown = false;
        OprateMode m_mode = OprateMode.none;

        #region 属性
        double m_scaleMax = 10;
        [Description("最大缩放倍数"), Category("自定义")]
        public double ScaleMax
        {
            get { return m_scaleMax; }
            set { m_scaleMax = value; }
        }
        [Description("最小缩放倍数"), Category("自定义")]
        double m_scaleMin = 0.02;
        public double ScaleMin
        {
            get { return m_scaleMin; }
            set { m_scaleMin = value; }
        }

        float m_scaleCur = 1.0f;
        [Description("当前缩放倍数"), Category("自定义")]
        public float ScaleCur
        {
            get { return m_scaleCur; }
            //set
            //{
            //    m_scaleCur = value;
            //    //lock(obj)
            //    //{
            //        //ImgItemsDraw.Clear();
            //        //foreach (DrawImg drawImg in ImgItems)
            //        //{
            //        //    try
            //        //    {
            //        //        var actBitmap = new Bitmap(drawImg.Img, new Size((int)(drawImg.Img.Width * m_scaleCur), (int)(drawImg.Img.Height * m_scaleCur)));
            //        //        DrawImg nw = new DrawImg(actBitmap, new Point((int)(drawImg.Location.X * m_scaleCur), (int)(drawImg.Location.Y * m_scaleCur)));
            //        //        ImgItemsDraw.Add(nw);
            //        //    }
            //        //    catch (Exception ex)
            //        //    {

            //        //    }
            //        //}
            //    //}
            //}
        }  //缩放比例
        [Description("显示十字架"), Category("自定义")]
        public bool ShowCross { get; set; } = false;
        [Description("允许移动"), Category("自定义")]
        public bool EnableMove { get; set; } = true;
        bool EnableDraw;

        #endregion

        //BufferedGraphics graphicsBuffer;
        public UCPreView()
        {
            DoubleBuffered = true;
            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
            SetStyle(ControlStyles.UserPaint, true);
            //using (Graphics graphics = CreateGraphics())
            //{
            //    graphicsBuffer = BufferedGraphicsManager.Current.Allocate(graphics, new Rectangle(0, 0, this.Width, this.Height));
            //}
            InitializeComponent();
            MouseWheel += UCPreView_MouseWheel;
            //drawRect.StartPoint = new PointF(200, 100);
            //drawRect.Size = new SizeF(100, 100);
            //drawRect.Angle = 45;
        }
        //CDrawRect drawRect = new CDrawRect();
        Object objLock = new object();
        #region 方法
        public void AddImg(Bitmap img, Point location = default, float angle = 0)
        {
            if (img == null)
                return;
            lock (objLock)
            {
                //ImgItems.Add(new DrawImg(img, location, angle));
                Rectangle rect = MatrixEx.GetBoard(location, new Size(img.Width, img.Height), angle);
                if (canvasImg == null)
                {
                    canvasImgRect = rect;
                    canvasImg = new Bitmap(canvasImgRect.Width, canvasImgRect.Height);
                }
                else
                {
                    if (canvasImgRect.Contains(rect) == false)
                    {
                        Bitmap oldImg = canvasImg;
                        Rectangle rectangle = canvasImgRect;
                        canvasImgRect = Rectangle.Union(canvasImgRect, rect);
                        canvasImg = new Bitmap(canvasImgRect.Width, canvasImgRect.Height);
                        canvasImg.CopyFrom(canvasImgRect.Location, oldImg, rectangle.Location, 0);
                    }
                }
                canvasImg.CopyFrom(canvasImgRect.Location, img, location, angle);
                //canvasImgBackup = (Bitmap)canvasImg.Clone();
                //canvasImg.Save("D:\\4.bmp");
                //var actBitmap = new Bitmap(img, new Size((int)(img.Width * m_scaleCur), (int)(img.Height * m_scaleCur)));
                //DrawImg nw = new DrawImg(actBitmap, new Point((int)(location.X * m_scaleCur), (int)(location.Y * m_scaleCur)));
                //ImgItemsDraw.Add(nw);
            }

        }

        public Bitmap GetImage(Rectangle rect, float angle)
        {
            try
            {
                if (rect.IsEmpty)
                    return null;
                var img = new Bitmap(rect.Width, rect.Height);
                Graphics g = Graphics.FromImage(img);
                g.RotateTransform(-angle);
                g.TranslateTransform(canvasImgRect.X - rect.X, canvasImgRect.Y - rect.Y);

                g.DrawImage(canvasImg, 0, 0, canvasImg.Width, canvasImg.Height);
                //img.CopyFrom(rect.Location, canvasImg, canvasImgRect.Location, -angle);
                return img;
            }
            catch (Exception)
            {

                return null;
            }



        }

        public void ClearImg()
        {
            lock (objLock)
            {
                canvasImg = null;
                canvasImgRect = Rectangle.Empty;
                //ImgItems.Clear();
                //ImgItemsDraw.Clear();
            }
        }
        public void AddDrawObject(CDrawObj obj)
        {
            m_objList.Add(obj);
        }
        public void AddDrawObjects(List<CDrawObj> objs)
        {
            m_objList.AddRange(objs);
        }
        public void RemoveDrawObject(CDrawObj obj)
        {
            m_objList.Remove(obj);
        }
        public void ClearDrawObject()
        {
            m_objList.Clear();
        }

        #endregion

        #region 事件
        private void UCPreView_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ControlKey)
            {
                m_isCtrl = true;
                if (m_mode == OprateMode.none)
                {
                    m_mode = OprateMode.move;
                }
            }

        }

        private void UCPreView_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.ControlKey)
            {
                m_isCtrl = false;
                if (m_mode == OprateMode.move)
                {
                    m_mode = OprateMode.none;
                }
            }
        }
        bool bHaveDrawImg;
        Bitmap DrawImg;
        private void UCPreView_MouseWheel(object sender, MouseEventArgs e)
        {
            if (m_isCtrl)
            {
                if (e.Delta > 0)//放大
                {
                    if (m_scaleCur >= m_scaleMax) return;
                    m_scaleCur = (float)Math.Min(m_scaleCur * m_zoomLevel, m_scaleMax);
                }
                else
                {
                    if (m_scaleCur <= m_scaleMin) return;
                    m_scaleCur = (float)Math.Max(m_scaleCur / m_zoomLevel, m_scaleMin);
                }
                UpdateImgOrgInCanvas(e.Location);
                if (canvasImg != null && m_scaleCur < 1)
                {

                    //Task.Run(() =>
                    //{
                    //    try
                    //    {
                    //        Stopwatch stopwatch = new Stopwatch();
                    //        stopwatch.Start();
                    //        bHaveDrawImg = false;
                    //        float scale = m_scaleCur;
                    //        DrawImg = new Bitmap(canvasImgBackup, new Size((int)(canvasImg.Width * m_scaleCur), (int)(canvasImg.Height * m_scaleCur)));
                    //        bHaveDrawImg = true;
                    //        Console.WriteLine($"scale:{stopwatch.ElapsedMilliseconds}");
                    //    }
                    //    catch (Exception ex)
                    //    {
                    //        Console.WriteLine("scale Exception:" + ex.Message);
                    //    }

                    //});
                }
                else
                    bHaveDrawImg = false;

                Invalidate();
            }
        }

        private void UCPreView_MouseDown(object sender, MouseEventArgs e)
        {
            Console.WriteLine("Canvas Down");
            lastMousePt = e.Location;
            //
            m_isLMouseDown = true;
            //if (m_isCtrl == false)
            //{
            //    curDrawObj = new CDrawRect() { StartPoint = PtPic2Img(e.Location) };
            //}
            //else
            //    curDrawObj = null;
        }

        private void UCPreView_MouseUp(object sender, MouseEventArgs e)
        {
            m_isLMouseDown = false;
            if (curDrawObj != null && lastMousePt != e.Location)
            {

                //objs.Add(curDrawObj);
                //curDrawObj = null;
            }
            if (m_isCtrl == false)
            {

            }


        }

        private void UCPreView_MouseMove(object sender, MouseEventArgs e)
        {
            curMousePt = e.Location;

            if (m_isCtrl && m_isLMouseDown && EnableMove)
            {
                UpdateImgOrgInCanvas(e.Location);
            }
            else
            {
                UpdatePosInImg(e.Location);
            }
            if (m_isLMouseDown && curDrawObj != null)
                curDrawObj.ReSize(m_curPosInImg);
            //Console.WriteLine(imgPt);
            if (m_isLMouseDown)
            {
                //curDrawObj.State = TrackerState.selected;
                //curDrawObj.ReSize(m_curPosInImg, CDrawObj.DirRight | CDrawObj.DirBottom);
            }
            else
            {
            }

            //rectangles[rectangles.Count - 1].Size = new Size();// = e.Y - rectangles[rectangles.Count - 1].Y;
            //Invalidate(new Rectangle(lastMousePt.X, lastMousePt.Y, curMousePt.X - lastMousePt.X+1, curMousePt.Y - lastMousePt.Y+1));
            Invalidate();
        }


        Brush BrushScale = new SolidBrush(Color.FromArgb(255, 255, 0, 0));
        protected override void OnPaint(PaintEventArgs e)
        {
            try
            {
                Stopwatch stopWatch = new Stopwatch();
                stopWatch.Start();
                Graphics g = e.Graphics;
                //Graphics g = graphicsBuffer.Graphics;
                Console.WriteLine(g.InterpolationMode);
                g.TranslateTransform(m_imgOrgInPic.X, m_imgOrgInPic.Y);
                long t1 = stopWatch.ElapsedMilliseconds;
                stopWatch.Restart();
                //for (int i = 0; i < ImgItemsDraw.Count; i++)
                //{
                //    g.DrawImage(ImgItemsDraw[i].Img, ImgItemsDraw[i].Location);
                //}
                if (bHaveDrawImg)
                    g.DrawImage(DrawImg, canvasImgRect.Location);


                g.ScaleTransform(m_scaleCur, m_scaleCur);
                long t2 = stopWatch.ElapsedMilliseconds;
                stopWatch.Restart();
                if (canvasImg != null && bHaveDrawImg == false)
                    g.DrawImage(canvasImg, canvasImgRect.Location);


                long t3 = stopWatch.ElapsedMilliseconds;
                stopWatch.Restart();
                //if (curDrawObj != null)
                //    curDrawObj.Draw(g, m_scaleCur);
                foreach (var item in m_objList)
                {
                    item.Draw(g, m_scaleCur);
                }
                long t4 = stopWatch.ElapsedMilliseconds;
                stopWatch.Restart();
                //-- 增加十字线中心
                if (ShowCross)
                {
                    Pen pen = new Pen(Color.Yellow);
                    int x = (canvasImgRect.Left + canvasImgRect.Right) / 2;
                    int y = (canvasImgRect.Top + canvasImgRect.Bottom) / 2;
                    g.DrawLine(pen, x, canvasImgRect.Top, x, canvasImgRect.Bottom);
                    g.DrawLine(pen, canvasImgRect.Left, y, canvasImgRect.Right, y);
                }

                //drawRect.Draw(g, m_scaleCur);
                g.ResetTransform();
                long t5 = stopWatch.ElapsedMilliseconds;
                stopWatch.Restart();
                g.DrawString(string.Format("{0:0.0}%", m_scaleCur * 100), m_font, BrushScale, Width - 100, 20);
                long t6 = stopWatch.ElapsedMilliseconds;
                stopWatch.Restart();
                Console.WriteLine($"绘图用时：t1={t1},t2={t2}，t3={t3}，t4={t4}，t5={t5}，t6={t6}");
                //graphicsBuffer.Render(e.Graphics);
                base.OnPaint(e);
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.Message);
            }
        }
        //private void UCPreView_Paint(object sender, PaintEventArgs e)
        //{

        //}
        #endregion
        //float lastScale = 1;

        //根据鼠标位置更新原点位置
        private void UpdateImgOrgInCanvas(Point picPt)
        {
            m_imgOrgInPic.X = picPt.X - m_curPosInImg.X * m_scaleCur;//e.X（鼠标位置）=m_imgOrgInPic.X+m_curPosInImg.X*m_imgZoom
            m_imgOrgInPic.Y = picPt.Y - m_curPosInImg.Y * m_scaleCur;
        }

        private void UpdatePosInImg(Point picPt)
        {
            m_curPosInImg.X = (picPt.X - m_imgOrgInPic.X) / m_scaleCur;
            m_curPosInImg.Y = (picPt.Y - m_imgOrgInPic.Y) / m_scaleCur;
            OnUpdatePos?.Invoke(this, new PosArgs((int)m_curPosInImg.X, (int)m_curPosInImg.Y));
        }

        //图片位置到画布位置
        private PointF PtPic2Img(Point picPt)
        {
            return new PointF((picPt.X - m_imgOrgInPic.X) / m_scaleCur, (picPt.Y - m_imgOrgInPic.Y) / m_scaleCur);
        }
        public void AutoSizeImage(bool bShowAll = true)
        {
            //if (ImgItems.Count <= 0)
            //    return;
            //PointF ltPt = default;//左上角
            //PointF rbPt = default;//右下角
            //foreach (DrawImg item in ImgItems)
            //{
            //    ltPt.X = Math.Min(ltPt.X, item.Location.X);
            //    ltPt.Y = Math.Min(ltPt.Y,item.Location.Y);
            //    rbPt.X = Math.Max(rbPt.X, item.Location.X + item.Img.Width);
            //    rbPt.Y = Math.Max(rbPt.Y, item.Location.Y + item.Img.Height);
            //}
            if (canvasImg == null) return;
            PointF ltPt = canvasImgRect.Location;//左上角
            PointF rbPt = new Point(canvasImgRect.Right, canvasImgRect.Bottom);//右下角
            double scaleX = 1;
            double scaleY = 1;
            if (Width > 0 || Height > 0)
            {
                scaleX = Width / (rbPt.X - ltPt.X);
                scaleY = Height / (rbPt.Y - ltPt.Y);
            }

            //e.X（鼠标位置）= m_imgOrgInPic.X + m_curPosInImg.X * m_imgZoom
            if (bShowAll)
                m_scaleCur = (float)Math.Min(scaleX, scaleY);
            else
                m_scaleCur = (float)Math.Max(scaleX, scaleY);
            //UpdateImgOrgInCanvas(canvasImgRect.)
            m_imgOrgInPic.X = Width / 2 - (rbPt.X + ltPt.X) / 2 * m_scaleCur;
            m_imgOrgInPic.Y = Height / 2 - (rbPt.Y + ltPt.Y) / 2 * m_scaleCur;
        }

        private void UCPreView_Load(object sender, EventArgs e)
        {

        }

        private void UCPreView_Resize(object sender, EventArgs e)
        {
            //using (Graphics graphics = CreateGraphics())
            //{
            //    graphicsBuffer = BufferedGraphicsManager.Current.Allocate(graphics, new Rectangle(0, 0, this.Width, this.Height));
            //}
        }

        //private void InitializeComponent()
        //{
        //    this.SuspendLayout();
        //    // 
        //    // UCPreView
        //    // 
        //    this.BackColor = System.Drawing.Color.Gray;
        //    this.Name = "UCPreView";
        //    this.Size = new System.Drawing.Size(468, 393);
        //    this.Load += new System.EventHandler(this.UCPreView_Load_1);
        //    this.ResumeLayout(false);

        //}

        //private void UCPreView_Load_1(object sender, EventArgs e)
        //{

        //}
    }
    public enum OprateMode
    {
        none,
        move,
    }

    public class DrawImg
    {
        public DrawImg(Bitmap bmp, Point location = default, float Angle = 0)
        {
            this.Img = bmp;
            this.Location = location;
            this.Angle = Angle;
        }
        public Point Location; //起点位置
        public float Angle; //角度
        public Bitmap Img; //图像
    }
    //按下左键，按下Ctrl，鼠标移动->移动画布，滚轮滚动->移动画布
    //按下左键，按下Ctrl，多选元件
    //按下左键，未按下Ctrl，在元件内，鼠标滚动，
    /// <summary>
    /// 当前鼠标位置
    /// </summary>
    public class PosArgs : EventArgs
    {
        public int x;
        public int y;
        public PosArgs(int x, int y)
        {
            this.x = x; this.y = y;
        }
    }
}
